package fr.bda.cloud.tray.file;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;

import fr.bda.cloud.data.DataDescriptor;
import fr.bda.cloud.data.StorageMode;
import fr.bda.cloud.storage.StorageUnit;
import fr.bda.cloud.storage.StorageUnitConfiguration;
import fr.bda.cloud.storage.StorageUnitFactory;
import fr.bda.cloud.tray.CloudTray;
import fr.bda.cloud.tray.CloudTrayDialog;
import fr.bda.cloud.tray.CloudTrayDialogController;
import fr.bda.cloud.util.CloudFileParser;

public class SaveFileDialogController extends CloudTrayDialogController {

	Dimension dialogDimension = new Dimension(800, 450);
	Dimension storageUnitSelectorPanelDimension = new Dimension(350, 300);

	public SaveFileDialogController(CloudTray cloudTray) {
		super(cloudTray);
		validators.add(new SaveFileDialogValidator(cloudTray));
	}

	@Override
	public <C extends CloudTrayDialogController> void initDialog(CloudTrayDialog<C> dialog) {
		if (SaveFileDialog.class.isInstance(dialog)) {

			final SaveFileDialog saveFileDialog = (SaveFileDialog) dialog;
			JPanel formPanel = saveFileDialog.getFormPanel();
			formPanel.setLayout(new BoxLayout(formPanel, BoxLayout.Y_AXIS));

			// Storage unit selector panel
			// -------------------------------
			JPanel storageUnitSelectorPanel = new JPanel();
			StorageUnitConfigurationModelList availableStorageUnitModel = new StorageUnitConfigurationModelList();
			saveFileDialog.availableStorageUnit = new JList<StorageUnitConfiguration>(availableStorageUnitModel);
			saveFileDialog.availableStorageUnit.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
			saveFileDialog.availableStorageUnit.setLayoutOrientation(JList.VERTICAL_WRAP);
			saveFileDialog.availableStorageUnit.setPreferredSize(storageUnitSelectorPanelDimension);
			JPanel availableStorageUnitContainerPanel = new JPanel(new BorderLayout());
			availableStorageUnitContainerPanel.add(new JLabel("Available storage unit"), BorderLayout.NORTH);
			availableStorageUnitContainerPanel.add(saveFileDialog.availableStorageUnit, BorderLayout.SOUTH);
			storageUnitSelectorPanel.add(availableStorageUnitContainerPanel);

			JPanel selectorButtonPanel = new JPanel(new GridLayout(0, 1));
			JButton btSelectAll = new JButton(">>");
			selectorButtonPanel.add(btSelectAll);
			JButton btSelectSome = new JButton(">");
			selectorButtonPanel.add(btSelectSome);
			JButton btReleaseSome = new JButton("<");
			selectorButtonPanel.add(btReleaseSome);
			JButton btReleaseAll = new JButton("<<");
			selectorButtonPanel.add(btReleaseAll);
			storageUnitSelectorPanel.add(selectorButtonPanel);

			List<StorageUnitConfiguration> configurations = cloudTray.getData().getStorageUnitConfigurations();
			StorageUnitConfigurationModelList selectedStorageUnitModel = new StorageUnitConfigurationModelList(configurations);
			saveFileDialog.selectedStorageUnit = new JList<StorageUnitConfiguration>(selectedStorageUnitModel);
			saveFileDialog.selectedStorageUnit.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
			saveFileDialog.selectedStorageUnit.setLayoutOrientation(JList.VERTICAL_WRAP);
			saveFileDialog.selectedStorageUnit.setPreferredSize(storageUnitSelectorPanelDimension);
			JPanel selectedStorageUnitContainerPanel = new JPanel(new BorderLayout());
			selectedStorageUnitContainerPanel.add(new JLabel("Selected storage unit"), BorderLayout.NORTH);
			selectedStorageUnitContainerPanel.add(saveFileDialog.selectedStorageUnit, BorderLayout.SOUTH);
			storageUnitSelectorPanel.add(selectedStorageUnitContainerPanel);

			formPanel.add(storageUnitSelectorPanel, BorderLayout.NORTH);

			// Save file selector panel
			// -------------------------------
			saveFileDialog.pathField = new JTextField(null, 50);
			saveFileDialog.browseButton = new JButton("BROWSE...");
			saveFileDialog.browseButton.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					JFileChooser fileChooser = new JFileChooser();
					fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
					fileChooser.showOpenDialog(saveFileDialog);
					File selectedDir = fileChooser.getSelectedFile();
					if (selectedDir != null) {
						String path = selectedDir.getAbsolutePath();
						saveFileDialog.pathField.setText(path);
					}
				}
			});
			JPanel fileSelectorPanel = new JPanel();
			fileSelectorPanel.add(new JLabel("File to save: "));
			fileSelectorPanel.add(saveFileDialog.pathField);
			fileSelectorPanel.add(saveFileDialog.browseButton);
			formPanel.add(fileSelectorPanel, BorderLayout.CENTER);

			// Storage mode selector panel
			// -------------------------------
			JPanel storageModeSelectorPanel = new JPanel();
			storageModeSelectorPanel.add(new JLabel("Storage mode: "));
			saveFileDialog.storageModeSelector = new JComboBox<StorageMode>(StorageMode.values());
			storageModeSelectorPanel.add(saveFileDialog.storageModeSelector);
			formPanel.add(storageModeSelectorPanel, BorderLayout.SOUTH);

			dialog.setSize(dialogDimension);

			btSelectSome.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					if (saveFileDialog.availableStorageUnit.getModel().getSize() > 0) {

						StorageUnitConfigurationModelList availableConfigurationModelList = (StorageUnitConfigurationModelList) saveFileDialog.availableStorageUnit.getModel();
						StorageUnitConfigurationModelList selectedConfigurationModelList = (StorageUnitConfigurationModelList) saveFileDialog.selectedStorageUnit.getModel();

						List<StorageUnitConfiguration> availableSeletedConfigurations = new ArrayList<>();
						for (int i : saveFileDialog.availableStorageUnit.getSelectedIndices()) {
							StorageUnitConfiguration sc = saveFileDialog.availableStorageUnit.getModel().getElementAt(i);
							if (sc != null) {
								availableSeletedConfigurations.add(sc);
							}
						}

						availableConfigurationModelList.removeStorageUnitConfigurations(availableSeletedConfigurations);
						selectedConfigurationModelList.addStorageUnitConfigurations(availableSeletedConfigurations);
					}
				}
			});

			btSelectAll.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					if (saveFileDialog.availableStorageUnit.getModel().getSize() > 0) {

						StorageUnitConfigurationModelList availableConfigurationModelList = (StorageUnitConfigurationModelList) saveFileDialog.availableStorageUnit.getModel();
						StorageUnitConfigurationModelList selectedConfigurationModelList = (StorageUnitConfigurationModelList) saveFileDialog.selectedStorageUnit.getModel();

						List<StorageUnitConfiguration> availableSeletedConfigurations = availableConfigurationModelList.getAllStorageUnitConfiguration();

						availableConfigurationModelList.removeStorageUnitConfigurations(availableSeletedConfigurations);
						selectedConfigurationModelList.addStorageUnitConfigurations(availableSeletedConfigurations);
					}
				}
			});

			btReleaseAll.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					if (saveFileDialog.selectedStorageUnit.getModel().getSize() > 0) {

						StorageUnitConfigurationModelList availableConfigurationModelList = (StorageUnitConfigurationModelList) saveFileDialog.availableStorageUnit.getModel();
						StorageUnitConfigurationModelList selectedConfigurationModelList = (StorageUnitConfigurationModelList) saveFileDialog.selectedStorageUnit.getModel();

						List<StorageUnitConfiguration> seletedConfigurations = selectedConfigurationModelList.getAllStorageUnitConfiguration();

						selectedConfigurationModelList.removeStorageUnitConfigurations(seletedConfigurations);
						availableConfigurationModelList.addStorageUnitConfigurations(seletedConfigurations);
					}
				}
			});

			btReleaseSome.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					if (saveFileDialog.selectedStorageUnit.getModel().getSize() > 0) {

						StorageUnitConfigurationModelList availableConfigurationModelList = (StorageUnitConfigurationModelList) saveFileDialog.availableStorageUnit.getModel();
						StorageUnitConfigurationModelList selectedConfigurationModelList = (StorageUnitConfigurationModelList) saveFileDialog.selectedStorageUnit.getModel();

						List<StorageUnitConfiguration> seletedConfigurations = new ArrayList<>();
						for (int i : saveFileDialog.selectedStorageUnit.getSelectedIndices()) {
							StorageUnitConfiguration sc = saveFileDialog.selectedStorageUnit.getModel().getElementAt(i);
							if (sc != null) {
								seletedConfigurations.add(sc);
							}
						}

						selectedConfigurationModelList.removeStorageUnitConfigurations(seletedConfigurations);
						availableConfigurationModelList.addStorageUnitConfigurations(seletedConfigurations);
					}
				}
			});
		}
	}

	@Override
	public <C extends CloudTrayDialogController> void saveDialogData(CloudTrayDialog<C> dialog) {
		if (SaveFileDialog.class.isInstance(dialog)) {

			final SaveFileDialog saveFileDialog = (SaveFileDialog) dialog;

			StorageUnitFactory storageUnitFactory = new StorageUnitFactory();

			File selectedFile = new File(saveFileDialog.pathField.getText().trim());
			List<StorageUnitConfiguration> selectedStorageUnitList = ((StorageUnitConfigurationModelList) saveFileDialog.selectedStorageUnit.getModel()).getAllStorageUnitConfiguration();
			StorageMode selectedStorageMode = (StorageMode) saveFileDialog.storageModeSelector.getSelectedItem();

			switch (selectedStorageMode) {
			case RAID_1:

				// Initialize a descriptor
				UUID uuid = UUID.randomUUID();
				DataDescriptor desc = new DataDescriptor();
				desc.setStorageMode(selectedStorageMode);
				desc.setSaveDate(new Date());
				desc.setOwner(cloudTray.getData().getUser().getLogin());
				desc.setFileUuid(uuid.toString());
				desc.setFileName(selectedFile.getName());
				desc.setFileSize(selectedFile.length());
				desc.setNbBlocs(1);
				desc.setBlocUuid(uuid.toString());
				desc.setBlocSize(selectedFile.length());
				desc.setDataUuid(uuid.toString());
				desc.setDataSize(selectedFile.length());
				desc.setStorageUnits(selectedStorageUnitList);

				// Save on storage units
				for (StorageUnitConfiguration suConf : selectedStorageUnitList) {
					StorageUnit su = storageUnitFactory.initStorageUnit(suConf);
					su.saveData(desc, CloudFileParser.readFile(selectedFile));
				}
				break;

			default:
				System.err.println("Storage mode [" + selectedStorageMode.name() + "] not managed");
				break;
			}
		}

	}

}
